﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace KQ.DCMMP.Common
{
    /// <summary>
    /// 正则生成器
    /// </summary>
    public static class RegexGenerator
    {
        public class CharItem
        {
            public CharItem(CharType type, string value)
            {
                Type = type;
                Value = value;
            }

            public CharType Type { get; set; }
            public string Value { get; set; }
        }

        public enum CharType
        {
            Default = 0,
            Chinese = 1,
            Upper = 2,
            Lower = 3,
            Number = 4,
            Symble = 5,
            /// <summary>
            /// 如括号一类的字符
            /// </summary>
            Special = 6
        }

        public enum RegexType
        {
            Default = 0,
            Start = 1,
            Split = 2,
            Chinese = 3,
            Upper = 4,
            Lower = 5,
            UpperLower = 6,
            Match = 7,
            End = 8
        }

        public enum RegexMode
        {
            /// <summary>
            /// 宽松模式
            /// 中文等实用[\u4e00-\u9fa5]代替
            /// 长度为范围限制
            /// </summary>
            Lax = 0,
            /// <summary>
            /// 严格模式
            /// 有中文则将中文作为一部分
            /// 字符长度也进行限制为特定个数
            /// </summary>
            Strict = 1
        }

        public class RegexItem
        {
            public int Sort { get; set; }
            public string Value { get; set; }
            public RegexType ItemType { get; set; }
        }

        /// <summary>
        /// 
        /// </summary>
        public class RegexItemComparer : IComparer<RegexItem>
        {
            public int Compare(RegexItem x, RegexItem y)
            {
                if (x == null)
                {
                    if (y == null)
                    {
                        // If x is null and y is null, they're
                        // equal. 
                        return 0;
                    }
                    else
                    {
                        // If x is null and y is not null, y
                        // is greater. 
                        return -1;
                    }
                }
                else
                {
                    // If x is not null...
                    //
                    if (y == null)
                    // ...and y is null, x is greater.
                    {
                        return 1;
                    }
                    else
                    {
                        // ...and y is not null, compare the 
                        // lengths of the two strings.
                        //
                        int retval = x.Sort - y.Sort;

                        if (retval != 0)
                        {
                            // If the strings are not of equal length,
                            // the longer string is greater.
                            //
                            return retval;
                        }
                    }
                }

                return 0;
            }
        }

        public static string SymbolPattern = @"[^\dA-Za-z\u4e00-\u9fa5]";
        public static Regex SymbolRegex = new Regex(@"[^\dA-Za-z\u4e00-\u9fa5]");

        /// <summary>
        /// 
        /// </summary>
        /// <param name="input"></param>
        /// <param name="mode"></param>
        /// <param name="valuLength"></param>
        /// <returns></returns>
        public static string GenerateRegex(string input, RegexMode mode = RegexMode.Lax, int valuLength = 2)
        {
            if (string.IsNullOrEmpty(input))
            {
                return string.Empty;
            }

            StringBuilder messageBuilder = new StringBuilder();
            Dictionary<int, CharItem> charDicts = new Dictionary<int, CharItem>();

            int standard = 128;
            //将字符串拆分为byte[]数组         
            char[] c = input.ToCharArray();

            //判断字符类型
            for (int i = 0; i < c.Length; i++)
            {
                if (c[i] >= standard)
                {
                    charDicts.Add(i, new CharItem(CharType.Chinese, c[i].ToString()));
                    continue;
                }
                else if (Char.IsUpper(c[i]))
                {
                    charDicts.Add(i, new CharItem(CharType.Upper, c[i].ToString()));
                    continue;
                }
                else if (Char.IsLower(c[i]))
                {
                    charDicts.Add(i, new CharItem(CharType.Lower, c[i].ToString()));
                    continue;
                }
                else if (Char.IsNumber(c[i]))
                {
                    charDicts.Add(i, new CharItem(CharType.Number, c[i].ToString()));
                    continue;
                }
                else if (c[i].IsRegexSpecial())
                {
                    charDicts.Add(i, new CharItem(CharType.Special, c[i].ToString()));
                    continue;
                }
                else// if(SymbolRegex.IsMatch(c[i].ToString()))
                {
                    charDicts.Add(i, new CharItem(CharType.Symble, c[i].ToString()));
                    continue;
                }
            }

            StringBuilder regexBuilder = new StringBuilder();

            //自动生成正则表达式
            int currentIndex = 0;
            CharType currentType = charDicts[currentIndex].Type;

            //添加起始符号
            regexBuilder.Append("^");
            //循环生成正则
            GenerateRegex(charDicts, currentIndex, currentType, regexBuilder, mode, valuLength);
            //添加终止符号
            regexBuilder.Append("$");

            return regexBuilder.ToString();
        }

        /// <summary>
        /// 嵌套生成正则表达式
        /// </summary>
        /// <param name="items"></param>
        /// <param name="index"></param>
        /// <param name="type"></param>
        /// <param name="regexBuilder"></param>
        /// <param name="mode"></param>
        /// <param name="valueLength"></param>
        private static void GenerateRegex(Dictionary<int, CharItem> items, int index, CharType type,
            StringBuilder regexBuilder, RegexMode mode = RegexMode.Lax, int valueLength = 2)
        {
            //当前索引值小于长度，继续生成
            if (index < items.Count)
            {
                int count = 0;
                int lastIndex = index;

                //最后的类型 主要用于相同字符的处理
                CharType lastType = CharType.Default;

                //保存连续的相同类型值
                StringBuilder valueBuilder = new StringBuilder();

                string value = string.Empty;

                //如果是符号，则直接使用符号
                if (type == CharType.Special)
                {
                    value = items[index].Value;
                }

                //判断下一位是不是相同的类型
                //直到另一种类型出现则停止
                for (int i = index; i < items.Keys.Count; i++)
                {
                    if (type == CharType.Special)
                    {
                        lastIndex = i + 1;

                        if (lastIndex < items.Count)
                        {
                            lastType = items[lastIndex].Type;
                        }
                        break;
                    }
                    else
                    {
                        if (type == items[i].Type)
                        {
                            count = count + 1;
                            valueBuilder.Append(items[i].Value);
                            lastIndex = i;
                            continue;
                        }
                    }

                    lastIndex = i;
                    lastType = items[i].Type;
                    break;
                }

                string length = string.Empty;

                #region CharType

                //判断类型
                switch (type)
                {
                    case CharType.Chinese:
                        if (mode == RegexMode.Lax)
                        {
                            //如果是开头，那么使用[\\u4e00-\\u9fa5]代替
                            //否则 直接使用字符
                            if (index == 0)
                            {
                                length = "{" + index.ToString() + "," + count.ToString() + "}"; ;
                                regexBuilder.Append("(").Append("[\\u4e00-\\u9fa5]").Append(length).Append(")");
                            }
                            else
                            {
                                regexBuilder.Append(valueBuilder.ToString());
                            }

                            //通用正则设置
                            //length = "{0,}";
                            //regexBuilder.Append("(").Append("[\\u4e00-\\u9fa5]").Append(length).Append(")");
                        }
                        else
                        {
                            //严格模式
                            regexBuilder.Append("(").Append(valueBuilder.ToString()).Append(")");
                        }

                        break;
                    case CharType.Lower:
                        if (mode == RegexMode.Lax)
                        {
                            if (index == 0)
                            {
                                length = "{" + index.ToString() + "," + count.ToString() + "}";
                                regexBuilder.Append("(").Append("[a-z]").Append(length).Append(")");
                            }
                            else
                            {
                                regexBuilder.AppendFormat("({0})", valueBuilder.ToString());
                            }

                            //通用正则设置
                            //length = "{0,}";
                            //regexBuilder.Append("(").Append("[a-z]").Append(length).Append(")");
                        }
                        else
                        {
                            //严格模式
                            regexBuilder.AppendFormat("({0})", valueBuilder.ToString());
                        }

                        break;
                    case CharType.Upper:
                        if (mode == RegexMode.Lax)
                        {
                            if (index == 0)
                            {
                                length = "{" + index.ToString() + "," + count.ToString() + "}";
                                regexBuilder.Append("(").Append("[A-Z]").Append(length).Append(")");
                            }
                            else
                            {
                                regexBuilder.AppendFormat("({0})", valueBuilder.ToString());
                            }

                            //通用正则设置
                            //length = "{0,}";
                            //regexBuilder.Append("(").Append("[A-Z]").Append(length).Append(")");
                        }
                        else if (mode == RegexMode.Strict)
                        {
                            //严格模式
                            regexBuilder.AppendFormat("({0})", valueBuilder.ToString());
                        }
                        break;
                    case CharType.Number:
                        //数字类型较为复杂
                        int maxCount = valueLength + 1;

                        if (mode == RegexMode.Lax)
                        {
                            //类似于1202这样的格式，取出右侧两位                
                            //012这样的格式，取出右侧三位
                            if (count >= maxCount)
                            {
                                int confirm = valueLength;
                                int residue = count - confirm;
                                length = "{" + string.Format("0,{0}", residue) + "}";
                                regexBuilder.Append("(").Append("[\\d]").Append(length).Append(")");

                                length = "{" + confirm.ToString() + "}";
                                regexBuilder.Append("(").Append("[\\d]").Append(length).Append(")");
                            }
                            else
                            {
                                length = "{" + count.ToString() + "}";
                                regexBuilder.Append("(").Append("[\\d]").Append(length).Append(")");
                            }
                        }
                        else if (mode == RegexMode.Strict)
                        {
                            //前一部分为数字
                            //后一部分为匹配项
                            //获取前一部分信息
                            string all = valueBuilder.ToString();

                            //全部为匹配项
                            if (count <= valueLength)
                            {
                                length = "{" + count.ToString() + "}";
                                regexBuilder.Append("(").Append("[\\d]").Append(length).Append(")");
                            }
                            else if (count > valueLength)
                            {
                                //前一部分作为固定值
                                int confirm = valueLength;
                                string prefix = all.Substring(0, all.Length - 3);
                                regexBuilder.Append("(").Append(prefix).Append(")");

                                //后一部分为匹配值
                                length = "{" + confirm.ToString() + "}";
                                regexBuilder.Append("(").Append("[\\d]").Append(length).Append(")");
                            }
                        }

                        break;
                    case CharType.Symble:
                        if (mode == RegexMode.Lax)
                        {
                            regexBuilder.AppendFormat("({0})", valueBuilder.ToString());

                            //通用正则设置
                            //所有的符号进行匹配
                            //length = "{" + string.Format("0,{0}", valueBuilder.Length) + "}";
                            //regexBuilder.Append("(").Append(SymbolPattern).Append(length).Append(")");
                        }
                        else
                        {
                            //严格模式
                            regexBuilder.AppendFormat("({0})", valueBuilder.ToString());
                        }
                        break;
                    case CharType.Special:
                        //特殊字符使用转义符
                        regexBuilder.AppendFormat(@"(\{0})", value.ToString());
                        break;
                    case CharType.Default:
                        break;
                }

                #endregion

                //判断是否还需要进行嵌套
                if (lastIndex < items.Count)
                {
                    if (index < lastIndex)
                    {
                        GenerateRegex(items, lastIndex, lastType, regexBuilder, mode, valueLength);
                    }
                }
            }

            return;
        }

    }
}